<?
    final class Principio_IPCalculator
    {
        protected static function addnull($binstr) 
        {
            return str_pad($binstr, 8, "0", STR_PAD_LEFT); 
        }
        
        protected static function bincalc($bin1,$bin2,$calc=1) 
        {
            //������������� �������� �� ��������
            $result1 = preg_split('//', $bin1, -1, PREG_SPLIT_NO_EMPTY);
            $result2 = preg_split('//', $bin2, -1, PREG_SPLIT_NO_EMPTY);
            for ($i=0;$i!=8;$i++)
            {	
                if ($calc==1) //�������� (1+1=1; 1+0=1; 0+0=0)
                {
                    if ($result1[$i]=="1" or $result2[$i]=="1")
                        $result3[$i]="1";
                    else 
                        $result3[$i]="0";
                }
                elseif ($calc==2) //��������� (������ ��� ������ ���� ������ ������ ������� (1-1=0; 1-0=1; 0-0=0))
                {
                    if ($result2[$i]=="0")
                        $result3[$i]="1";
                    else
                        $result3[$i]="0";
                }
                elseif ($calc==3) //���������� � (1+1=1; 1+0=0; 0+1=0; 0+0=0)
                {
                    if ($result1[$i]=="1" and $result2[$i]=="1")
                        $result3[$i]="1";
                    else
                        $result3[$i]="0";
                }
            }
        
            return implode("", $result3); //���������� ������ � ������
        }
        
        public static function calculator($ip, $mask)
        {
            $result = array();
            
            // ip parsing
            $ip = rtrim(ltrim($ip," .")," ."); 
            list($ip1,$ip2,$ip3,$ip4)=explode(".",$ip);
            $bit_ip1 = self::addnull(decbin($ip1));
            $bit_ip2 = self::addnull(decbin($ip2));
            $bit_ip3 = self::addnull(decbin($ip3));
            $bit_ip4 = self::addnull(decbin($ip4));
            $bit_ip=$bit_ip1.".".$bit_ip2.".".$bit_ip3.".".$bit_ip4;
            
            //mask parsing
            $mask = rtrim(ltrim($mask," ./")," ./");
            if (substr_count($mask,".")>0) //���� ����� � ���� ���
            {
                list($ip_mask1,$ip_mask2,$ip_mask3,$ip_mask4)=explode(".",$mask);
            
                $ip_mask=$mask;
            
                $bit_mask1 = self::addnull(decbin($ip_mask1));
                $bit_mask2 = self::addnull(decbin($ip_mask2));
                $bit_mask3 = self::addnull(decbin($ip_mask3));
                $bit_mask4 = self::addnull(decbin($ip_mask4));
            
                $bit_mask=$bit_mask1.".".$bit_mask2.".".$bit_mask3.".".$bit_mask4; //�������� �����
            } 
            else //���� ������� �����, ��������� � � ���� ���
            {
                $bit_mask=""; //string
                for ($i=1;$i!=33;$i++) {
                    if ($i<=$mask) $bit_mask.="1";
                    else $bit_mask.="0";
                    if ($i==8 or $i==16 or $i==24) $bit_mask.=".";
            
                }
            
                list($bit_mask1,$bit_mask2,$bit_mask3,$bit_mask4)=explode(".",$bit_mask);
                
                $ip_mask1=bindec($bit_mask1);
                $ip_mask2=bindec($bit_mask2);
                $ip_mask3=bindec($bit_mask3);
                $ip_mask4=bindec($bit_mask4);
            
                $ip_mask=$ip_mask1.".".$ip_mask2.'.'.$ip_mask3.'.'.$ip_mask4;
            }
            $bit_count=substr_count($bit_mask,"1");
            
            //--------------------------
            //�������� ����� (wildcat for cisco) (255 - mask section)
            //--------------------------
            
            $cisco_bit_mask1 = self::bincalc("11111111",$bit_mask1,2);
            $cisco_bit_mask2 = self::bincalc("11111111",$bit_mask2,2);
            $cisco_bit_mask3 = self::bincalc("11111111",$bit_mask3,2);
            $cisco_bit_mask4 = self::bincalc("11111111",$bit_mask4,2);
            $cisco_mask1 = bindec($cisco_bit_mask1);
            $cisco_mask2 = bindec($cisco_bit_mask2);
            $cisco_mask3 = bindec($cisco_bit_mask3);
            $cisco_mask4 = bindec($cisco_bit_mask4);
            
            $cisco_mask = $cisco_mask1.".".$cisco_mask2.".".$cisco_mask3.".".$cisco_mask4;
            $cisco_bit_mask = $cisco_bit_mask1.".".$cisco_bit_mask2.".".$cisco_bit_mask3.".".$cisco_bit_mask4;
            
            //--------------------------
            //broadcast = ip + invert_mask
            //--------------------------
            
            $bc_bit_ip1 = self::bincalc($bit_ip1,$cisco_bit_mask1);
            $bc_bit_ip2 = self::bincalc($bit_ip2,$cisco_bit_mask2);
            $bc_bit_ip3 = self::bincalc($bit_ip3,$cisco_bit_mask3);
            $bc_bit_ip4 = self::bincalc($bit_ip4,$cisco_bit_mask4);
            $bc_ip1 = bindec($bc_bit_ip1);
            $bc_ip2 = bindec($bc_bit_ip2);
            $bc_ip3 = bindec($bc_bit_ip3);
            $bc_ip4 = bindec($bc_bit_ip4);
            
            $bc_ip=$bc_ip1.".".$bc_ip2.".".$bc_ip3.".".$bc_ip4;
            $bc_bit_ip=$bc_bit_ip1.".".$bc_bit_ip2.".".$bc_bit_ip3.".".$bc_bit_ip4;
            
            //--------------------------
            //network = ip + mask (AND)
            //--------------------------
            
            $net_bit_ip1 = self::bincalc($bit_ip1,$bit_mask1,3);
            $net_bit_ip2 = self::bincalc($bit_ip2,$bit_mask2,3);
            $net_bit_ip3 = self::bincalc($bit_ip3,$bit_mask3,3);
            $net_bit_ip4 = self::bincalc($bit_ip4,$bit_mask4,3);
            $net_ip1 = bindec($net_bit_ip1);
            $net_ip2 = bindec($net_bit_ip2);
            $net_ip3 = bindec($net_bit_ip3);
            $net_ip4 = bindec($net_bit_ip4);
            
            $net_ip=$net_ip1.".".$net_ip2.".".$net_ip3.".".$net_ip4;
            $net_bit_ip=$net_bit_ip1.".".$net_bit_ip2.".".$net_bit_ip3.".".$net_bit_ip4;
            $default_gw = $net_ip1.".".$net_ip2.".".$net_ip3.".".($net_ip4+1);
            $min_ip = $net_ip1.".".$net_ip2.".".$net_ip3.".".($net_ip4+2);
            
            //--------------------------
            //ip min (network + 1)
            //--------------------------
            
            $net_min_ip=$net_ip1.".".$net_ip2.".".$net_ip3.".".($net_ip4+1);
            $net_min_bit_ip=$net_bit_ip1.".".$net_bit_ip2.".".$net_bit_ip3.".".self::addnull(decbin($net_ip4+1));
            
            //--------------------------
            //ip max (broadcast - 1)
            //--------------------------
            
            $net_max_ip=$bc_ip1.".".$bc_ip2.".".$bc_ip3.".".($bc_ip4-1);
            $net_max_bit_ip=$bc_bit_ip1.".".$bc_bit_ip2.".".$bc_bit_ip3.".".self::addnull(decbin($bc_ip4-1));
            
            //--------------------------
            //number of hosts = 2 ^ (32 - bitcount) - 2
            //
            //network class:
            //0 - class A
            //10 - Class B
            //110 - Class C
            //1110 - Class D
            //11110 - Class E
            //--------------------------
            
            $host_count=abs(pow(2, 32-$bit_count)-2);
            
            
            if ($bit_count>=16 and $bit_count<=32) 
            
            if (substr($net_bit_ip1, 0, 1)=="0") $host_class="<font color=green>Class A</font>";
            elseif (substr($net_bit_ip1, 0, 2)=="10") $host_class="<font color=green>Class B</font>";
            elseif (substr($net_bit_ip1, 0, 3)=="110") $host_class="<font color=green>Class C</font>";
            elseif (substr($net_bit_ip1, 0, 4)=="1110") $host_class="<font color=green>Class D</font>";
            elseif (substr($net_bit_ip1, 0, 5)=="11110") $host_class="<font color=green>Class E</font>";
            else $host_class="<font color=red>Class invalid</font>";
            
            $result["ip"] = $ip;
            $result["netmask"] = $ip_mask;
            $result["mask_bit"] = $bit_count;
            $result["broadcast"] = $bc_ip;
            $result["range_from"] = $min_ip;
            $result["range_to"] = $net_max_ip;
            $result["netname"] = $net_ip;
            $result["default_gw"] = $default_gw;
            
            return $result;
        }
    }
?>